﻿using System;
using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Emit;

namespace Vtron.ATSP.Infrastructure
{
    public static class ReflectionFactory
    {
        private static readonly IDictionary<string, Delegate> m_Creators = new Dictionary<string, Delegate>();

        public static T CreateObject<T>(string classFullName)
        {
            return (T)CreateDelegate<T>(classFullName)();
        }

        private static Func<T> CreateDelegate<T>(string classFullName)
        {
            if (m_Creators.ContainsKey(classFullName))
            {
                return m_Creators[classFullName] as Func<T>;
            }

            Func<T> f = null;
            Type t = Type.GetType(classFullName, false);
            ConstructorInfo ci = t.GetConstructor(Type.EmptyTypes);
            DynamicMethod dm = new DynamicMethod(string.Empty, typeof(T), Type.EmptyTypes);
            ILGenerator gen = dm.GetILGenerator();
            gen.Emit(OpCodes.Newobj, ci);
            gen.Emit(OpCodes.Ret);
            f = (Func<T>)dm.CreateDelegate(typeof(Func<T>));

            lock (m_Creators)
            {
                if (!m_Creators.ContainsKey(classFullName))
                {
                    m_Creators.Add(classFullName, f);
                }
            }

            return f;
        }
    }
}
